package com.svpino.netflix.parsers;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;

import com.svpino.netflix.ProxyImpl;
import com.svpino.netflix.model.Format;
import com.svpino.netflix.model.Language;

public class FormatParser extends ListParser<Format> {

	public FormatParser(ProxyImpl connection) {
		super(connection);
	}

	@Override
	public List<Format> list(Element... elements) {
		try {
			Element element = elements[0];
			HashMap<String, String> screenFormats = parseScreenFormats(elements.length >= 2 ? elements[1] : null);
			HashMap<String, List<Language>> languages = parseLanguagesAndAudio(elements.length >= 3 ? elements[2] : null);

			List<Format> list = new ArrayList<Format>();

			NodeList nodeList = element.getElementsByTagName("availability");
			for (int i = 0; i < nodeList.getLength(); i++) {
				Element itemElement = (Element) nodeList.item(i);

				NamedNodeMap attributes = itemElement.getElementsByTagName("category").item(0).getAttributes();
				String term = attributes.getNamedItem("term").getNodeValue();

				Date availableFrom = null;
				if (element.hasAttribute("available_from")) {
					availableFrom = new Date(Long.parseLong(element.getAttribute("available_from")) * 1000);
				}

				Date availableUntil = null;
				if (element.hasAttribute("available_until")) {
					availableUntil = new Date(Long.parseLong(element.getAttribute("available_until")) * 1000);
				}

				list.add(new Format(term, availableFrom, availableUntil, screenFormats.get(term), languages.get(term)));
			}

			return list;
		}
		catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	private HashMap<String, String> parseScreenFormats(Element element) throws XPathExpressionException {
		HashMap<String, String> screenFormats = new HashMap<String, String>();

		if (element != null) {
			XPathFactory factory = XPathFactory.newInstance();
			XPath xPath = factory.newXPath();
			XPathExpression screenFormatXPathExpression = xPath.compile("./category[@scheme='http://api.netflix.com/categories/screen_formats']");
			XPathExpression titleFormatXPathExpression = xPath.compile("./category[@scheme='http://api.netflix.com/categories/title_formats']");

			NodeList nodeList = element.getElementsByTagName("screen_format");
			for (int i = 0; i < nodeList.getLength(); i++) {
				Element screenFormatElement = (Element) nodeList.item(i);

				String screenFormat = ((Element) ((NodeList) screenFormatXPathExpression.evaluate(screenFormatElement, XPathConstants.NODESET)).item(0)).getAttribute("term");
				String titleFormat = ((Element) ((NodeList) titleFormatXPathExpression.evaluate(screenFormatElement, XPathConstants.NODESET)).item(0)).getAttribute("term");

				screenFormats.put(titleFormat, screenFormat);
			}
		}

		return screenFormats;
	}
	
	private HashMap<String, List<Language>> parseLanguagesAndAudio(Element element) throws XPathExpressionException {
		HashMap<String, List<Language>> languagesFormat = new HashMap<String, List<Language>>();
		
		if (element != null) {
			XPathFactory factory = XPathFactory.newInstance();
			XPath xPath = factory.newXPath();
			XPathExpression titleFormatXPathExpression = xPath.compile("./category[@scheme='http://api.netflix.com/categories/title_formats']");
			
			NodeList nodeList = element.getElementsByTagName("language_audio_format");
			for (int i = 0; i < nodeList.getLength(); i++) {
				List<Language> languages = new ArrayList<Language>();
				
				Element languageAudioFormatElement = (Element) nodeList.item(i);
				Element titleFormatElement = (Element) ((NodeList) titleFormatXPathExpression.evaluate(languageAudioFormatElement, XPathConstants.NODESET)).item(0);
				
				String titleFormat = titleFormatElement.getAttribute("term");
				
				NodeList languageNodeList = titleFormatElement.getChildNodes();
				for(int j = 0; j <languageNodeList.getLength(); j++) {
					if (languageNodeList.item(j) instanceof Element && languageNodeList.item(j).getNodeName().equals("category")) {
						String language = ((Element)languageNodeList.item(j)).getAttribute("term");
						String audio = ((Element)((Element)languageNodeList.item(j)).getChildNodes().item(0)).getAttribute("term");
						languages.add(new Language(language, audio));
					}
				}
				
				languagesFormat.put(titleFormat, languages);
			}
		}

		return languagesFormat;
	}

}
